import { createI18n } from 'vue-i18n'
import { messages, SupportLocaleTuple, SupportLocale, SUPPORT_LOCALES } from '@/locals'
import { onUnmounted } from 'vue'
import { setCookie, getCookie } from '@/utils/utils'

/**
 * onLocaleChanged queue
 */
const localeChangeQueue = new Set<() => void>();

/**
 * i18n instance
 */
export const i18n = createI18n({
    legacy: false,
    locale: SUPPORT_LOCALES[0],
    fallbackLocale: SUPPORT_LOCALES[0],
    messages,
})

/**
 * Locale message translation
 * @remarks — About details functions, See the {@link i18n.global.t t}
 */
export const t = i18n.global.t

/**
 * Set locale
 * @description Always exec this function when you need to change locale
 * @param locale 
 */
export function setLocale(locale: SupportLocale) {
    if (!SUPPORT_LOCALES.includes(locale)) {
        return
    }

    i18n.global.locale.value = locale
    setHTMLLangAttribute(locale);
    setCookieLang(locale)

    // Exec the locale change queue
    try {
        for (const fn of localeChangeQueue) {
            fn()
        }
    } catch (error) {
        console.error(error)
    }
}

/**
 * add locale change listener
 * @param fn 
 */
export function onLocaleChanged(fn: () => void, {
    needClear = true
} = {}) {
    if (localeChangeQueue.has(fn)) {
        return
    }

    // Add in queue
    localeChangeQueue.add(fn)

    if (needClear) {
        // Delete queue item when unmount
        onUnmounted(() => {
            localeChangeQueue.delete(fn)
        })
    }
}

/**
 * Init locale setting
 */
export function initLocaleSetting() {
    let locale = getCookie("lang") as SupportLocale;

    if (!SUPPORT_LOCALES.includes(locale)) {
        let fallbackLocale: SupportLocale | undefined
        /**
         * User language preference in cookie, navigator.language and navigator.languages
         * And includes user language prefix
         */
        const userLanguages = [
            locale,
            (locale || '').replace(/-.*/, ''),
            navigator.language,
            (navigator.languages[0] || ''),
            (navigator.languages[0] || '').replace(/-.*/, ''),
            ...(navigator.languages || []),
            (navigator.language || '').replace(/-.*/, ''),
            ...(navigator.languages || []).map((e) => e.replace(/-.*/, ''))
        ]
        for (const language of userLanguages) {
            if ((SUPPORT_LOCALES as unknown as string[]).includes(language)) {
                locale = language as SupportLocale;
                break
            }
            // Match support locales prefix with user language
            fallbackLocale = fallbackLocale || matchLocalePrefix(SUPPORT_LOCALES, language)
        }
        if (fallbackLocale) {
            locale = fallbackLocale
        }
    }

    setLocale(locale);
}

/**
 * Match support locales prefix with user language
 * @param supportLocales
 * @param userLanguage
 * @returns 
 */
function matchLocalePrefix(supportLocales: SupportLocaleTuple, userLanguage: string) {
    for (const supportLocale of supportLocales) {
        let prefix = supportLocale.replace(/-.*/, '');
        if (prefix === userLanguage) {
            return supportLocale
        }
    }
}

function setHTMLLangAttribute(lang: SupportLocale) {
    document.querySelector("html")?.setAttribute("lang", lang)
}

function setCookieLang(lang: SupportLocale) {
    setCookie("lang", lang, 99999)
}
